泛型可以讓 Move 在使用上更靈活,在其他語言亦是如此。
泛型是具體類型或其他屬性的抽象替代品。在 Move 中,泛型可以應用於 Struct
和 Function
// 在之前篇章有介紹過的 struct
module Storage {
struct Box {
value: u64
}
}
// 使用泛型的 struct
module Storage {
struct Box<T> {
value: T
}
}
struct Foo<T> has copy, drop { x: T }
address 0x3 {
module M {
struct Box<T> has drop {
value: T
}
public fun create_box<T>(value: T): Box<T> {
Box<T> { value }
}
public fun value<T: copy>(box: &Box<T>): T {
box.value
}
}
}
// 在 main function 中使用
script {
use 0x3::M;
use 0x1::Debug;
fun main() {
// 使用 bool
let bool_box = M::create_box<bool>(true);
let box_value = M::value(&bool_box);
assert(box_value, 0); // true
// 使用 integer
let u64_box = M::create_box<u64>(10000);
let box_value_2 = M::value(&u64_box);
assert(box_value2, 10000); // true
}
}
我們通過向 struct 添加泛型,使 Box 可以使用任何類型創建,無論是 bool, u64, address, 甚至是另一個 box 和 另一個結構。
在前幾篇中,我們介紹過能力,他們可以在泛型中檢查或約束
// 在 function 中
fun name<T: copy>() {} // 參數允許被複製
fun name<T: copy + drop>() {} // 參數可以 drop 掉
fun name<T: key + store + drop + copy>() {} // 擁有四項能力
// 在 Struct 中
struct name<T: copy + drop> { value: T } // T 有複製和 drop 能力
struct name<T: store> { value: T } // T 有儲存在全局儲存
加號 (+) 語法唯一用在這邊
參數和 struct 分別可以搭配 type 能力
module Storage {
// Box 可以被儲存
struct Box<T: store> has key, store {
content: T
}
}
Move 的容器能力會自動受到其內容限制,
例如有一個具有複製,刪除和儲存的 Struct, 而內部結構只有 drop,則無法複製或儲存該容器,解決方法是,容器需要對內部類型有約束。
module Storage {
// 沒有任何能力的 struct
struct Error {}
// Box 能力會被 T 能力影響, constents 將無任何能力
struct Box<T> has copy, drop {
contents: T
}
// 這樣只會產生沒有 copy 和 drop 能力的 contents
// 如果 script 要使用時將會 error
public fun create_box(): Box<Error> {
Box { contents: Error {} }
}
}
我們可以這樣宣告,讓 inner type 遵循 parent’s 能力
// T 擁有 parent's copy 和 drop 能力
struct Box<T: copy + drop> has copy, drop {
contents: T
}
使用 <>
和逗號使用多個泛型
module Storage {
struct Box<T> {
value: T
}
struct Shelf<T1, T2> {
box_1: Box<T1>,
box_2: Box<T2>
}
public fun create_shelf<Type1, Type2>(
box_1: Box<Type1>,
box_2: Box<Type2>
): Shelf<Type1, Type2> {
Shelf {
box_1,
box_2
}
}
}
並非必須使用泛型中指定得每種類型
module Storage {
struct Abroad {}
struct Local {}
struct Box<T, Destination> {
value: T
}
// 使用泛型當作某些操作的約束,我們後面介紹資源概念時會再提到
public fun create_box<T, Dest>(value: T): Box<T, Dest> {
Box { value }
}
}
script {
use 0x4::Storage;
fun main() {
// value will be of type Storage::Box<bool>
let _ = Storage::create_box<bool, Storage::Abroad>(true);
let _ = Storage::create_box<u64, Storage::Abroad>(1000);
let _ = Storage::create_box<u128, Storage::Local>(1000);
let _ = Storage::create_box<address, Storage::Local>(0x1);
// or even u64 destination!
let _ = Storage::create_box<address, u64>(0x1);
}
}
本篇介紹了大部分語言都有的泛型, Move 可以使用在 struct 和 function 中,同時搭配 type 能力來約束。讓我們 Move to Day 15